package com.mvity.framework.common.dao.impl;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Projections;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Repository;

import com.mvity.framework.common.base.BaseEntity;
import com.mvity.framework.common.dao.BaseHibernateDao;

/**
 * Hibernate DAO 基类
 * 
 * @author vity
 * @date 2012-3-15
 * @mail vity.1215@gmail.com
 */
@Repository(value = "baseHibernateDao")
public class BaseHibernateDaoImpl implements Serializable, BaseHibernateDao {

	private static final long serialVersionUID = 6825746809107385011L;

	protected static final Logger logger = LoggerFactory.getLogger(BaseHibernateDaoImpl.class);

	@Resource
	protected SessionFactory sessionFactory;

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.mvity.framework.common.dao.impl.BaseHibernateDao#getSession()
	 */
	@Override
	public Session getSession() {
		return sessionFactory.getCurrentSession();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.mvity.framework.common.dao.impl.BaseHibernateDao#save(T)
	 */
	@Override
	public <T extends BaseEntity> T save(T model) {
		getSession().save(model);
		getSession().flush();
		return model;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.mvity.framework.common.dao.impl.BaseHibernateDao#saveOrUpdate(T)
	 */
	@Override
	public <T extends BaseEntity> T saveOrUpdate(T model) {
		if (StringUtils.isNotBlank(model.getId())) {
			model.setLastModifyTime(new Date());
		}
		getSession().saveOrUpdate(model);
		getSession().flush();
		return model;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.mvity.framework.common.dao.impl.BaseHibernateDao#update(T)
	 */
	@Override
	public <T extends BaseEntity> void update(T model) {
		Date date = new Date();
		model.setLastModifyTime(date);
		getSession().update(model);
		getSession().flush();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.mvity.framework.common.dao.impl.BaseHibernateDao#merge(T)
	 */
	@Override
	public <T extends BaseEntity> void merge(T model) {
		Date date = new Date();
		model.setLastModifyTime(date);
		getSession().merge(model);
		getSession().flush();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.mvity.framework.common.dao.impl.BaseHibernateDao#remove(java.lang
	 * .Class, PK)
	 */
	@Override
	public <T extends BaseEntity, PK extends Serializable> void remove(Class<T> entityClass, PK id) {
		removeObject(get(entityClass, id));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.mvity.framework.common.dao.impl.BaseHibernateDao#removeObject(T)
	 */
	@Override
	public <T extends BaseEntity> void removeObject(T model) {
		Date date = new Date();
		model.setDelete(true);
		model.setLastModifyTime(date);
		getSession().update(model);
		getSession().flush();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.mvity.framework.common.dao.impl.BaseHibernateDao#delete(java.lang
	 * .Class, PK)
	 */
	@Override
	public <T extends BaseEntity, PK extends Serializable> void delete(Class<T> entityClass, PK id) {
		getSession().delete(get(entityClass, id));
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.mvity.framework.common.dao.impl.BaseHibernateDao#deleteObject(T)
	 */
	@Override
	public <T extends BaseEntity> void deleteObject(T model) {
		getSession().delete(model);
		getSession().flush();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.mvity.framework.common.dao.impl.BaseHibernateDao#get(java.lang.Class,
	 * PK)
	 */
	@Override
	@SuppressWarnings("unchecked")
	public <T extends BaseEntity, PK extends Serializable> T get(Class<T> entityClass, PK id) {
		return (T) getSession().get(entityClass, id);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.mvity.framework.common.dao.impl.BaseHibernateDao#countAll(java.lang
	 * .Class)
	 */
	@Override
	public <T extends BaseEntity> int countAll(Class<T> entityClass) {
		Criteria criteria = getSession().createCriteria(entityClass);
		criteria.setProjection(Projections.rowCount());
		return ((Long) criteria.uniqueResult()).intValue();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.mvity.framework.common.dao.impl.BaseHibernateDao#listAll(java.lang
	 * .Class)
	 */
	@Override
	@SuppressWarnings("unchecked")
	public <T extends BaseEntity> List<T> listAll(Class<T> entityClass) {
		String hql = "from " + entityClass.getName() + " as entity ";
		return getSession().createQuery(hql).list();
	}
}
